///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __MATERIALMANAGER_H__
#define __MATERIALMANAGER_H__

#include "OgrePrerequisites.h"

#include "OgreSingleton.h"
#include "OgreResourceManager.h"
#include "OgreMaterial.h"
#include "OgreStringVector.h"
#include "OgreMaterialSerializer.h"

namespace Ogre {


	
	
	
    class _OgreExport MaterialManager : public ResourceManager, public Singleton<MaterialManager>
    {
	public:
		
		class Listener
		{
		public:
            
            virtual ~Listener() { }
			
			virtual Technique* handleSchemeNotFound(unsigned short schemeIndex, 
				const String& schemeName, Material* originalMaterial, unsigned short lodIndex, 
				const Renderable* rend) = 0;

		};

    protected:

        /// Default Texture filtering - minification
        FilterOptions mDefaultMinFilter;
        /// Default Texture filtering - magnification
        FilterOptions mDefaultMagFilter;
        /// Default Texture filtering - mipmapping
        FilterOptions mDefaultMipFilter;
        /// Default Texture anisotropy
        unsigned int mDefaultMaxAniso;
        /// Serializer - Hold instance per thread if necessary
        OGRE_THREAD_POINTER(MaterialSerializer, mSerializer);
		/// Default settings
		MaterialPtr mDefaultSettings;
		/// Overridden from ResourceManager
		Resource* createImpl(const String& name, ResourceHandle handle, 
			const String& group, bool isManual, ManualResourceLoader* loader,
            const NameValuePairList* params);

		/// Scheme name -> index. Never shrinks! Should be pretty static anyway
		typedef map<String, unsigned short>::type SchemeMap;
		/// List of material schemes
		SchemeMap mSchemes;
		/// Current material scheme
		String mActiveSchemeName;
		/// Current material scheme
		unsigned short mActiveSchemeIndex;

		/// The list of per-scheme (and general) material listeners
		typedef list<Listener*>::type ListenerList;
		typedef std::map<String, ListenerList> ListenerMap;
		ListenerMap mListenerMap;

    public:
		/// Default material scheme
		static String DEFAULT_SCHEME_NAME;
		
        
        MaterialManager();

        
        virtual ~MaterialManager();

		
		void initialise(void);
        
		
        void parseScript(DataStreamPtr& stream, const String& groupName);


        
        virtual void setDefaultTextureFiltering(TextureFilterOptions fo);
        
        virtual void setDefaultTextureFiltering(FilterType ftype, FilterOptions opts);
        
        virtual void setDefaultTextureFiltering(FilterOptions minFilter, FilterOptions magFilter, FilterOptions mipFilter);

		/// get the default texture filtering
        virtual FilterOptions getDefaultTextureFiltering(FilterType ftype) const;

        
		void setDefaultAnisotropy(unsigned int maxAniso);
		/// get the default maxAnisotropy
		unsigned int getDefaultAnisotropy() const;

        
		virtual MaterialPtr getDefaultSettings(void) const { return mDefaultSettings; }

		
		virtual unsigned short _getSchemeIndex(const String& name);
		
		virtual const String& _getSchemeName(unsigned short index);
		
		virtual unsigned short _getActiveSchemeIndex(void) const;

		
		virtual const String& getActiveScheme(void) const;
		
		
		virtual void setActiveScheme(const String& schemeName);

		
		virtual void addListener(Listener* l, const Ogre::String& schemeName = StringUtil::BLANK);

		
		virtual void removeListener(Listener* l, const Ogre::String& schemeName = StringUtil::BLANK);

		/// Internal method for sorting out missing technique for a scheme
		virtual Technique* _arbitrateMissingTechniqueForActiveScheme(
			Material* mat, unsigned short lodIndex, const Renderable* rend);

        
        static MaterialManager& getSingleton(void);
        
        static MaterialManager* getSingletonPtr(void);

    };
	
	

}

#endif
